package groep1.filter;

import groep1.ObjectRepresentation;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import bluej.debugmgr.inspector.FieldInfo;

public abstract class FilterHierarchyObject {
	
	public static void main(String[] args) {
		String str = "test";
		System.out.println(str.substring(0, str.length())); // test
	}

	public FilterHierarchyObject parseRegex(String regex, HashSet<ObjectRepresentation> objects){
		regex = regex.trim(); // remove leading and trailing spaces
		if (checkOuterBrackets(regex)) { // haakjes rond geheel
			return parseRegex(regex.substring(1, regex.length()-1), objects); // binnen de haakjes
		} else {
			int op = findOperator(regex); // op heeft positie van operator
			switch(op) {
				case(0): return new NotFilter(regex.substring(5), objects);
				case(Integer.MAX_VALUE): return new FilterObject(regex, objects);
				default: return handleOperator(op, regex, objects); // operator op positie 'op' uitvoeren
			}
		}
	}
	
	private FilterHierarchyObject handleOperator(int op, String regex, HashSet<ObjectRepresentation> objects) {
		String operator = regex.substring(op+1, op+3);
		if (operator.equals("en"))
			return new AndFilter(regex.substring(0, op), regex.substring(op+4), objects);
		else
			return new OrFilter(regex.substring(0, op), regex.substring(op+4), objects);
	}

	private int findOperator(String regex) {
		char[] letters = regex.toCharArray();
		int teller = 0;
		int j = Integer.MAX_VALUE;
		int i = 0;
		while (i <= regex.length()-1) {
			String karakter = new Character(letters[i]).toString();
			if (karakter.equals(" ") && i+3 < regex.length()) { // mogelijk operator
				String rest = new Character(letters[i+1]).toString() + new Character(letters[i+2]).toString() + new Character(letters[i+3]).toString();
				if (rest.equals("en ") && teller == 0) { // AND
					return i;
				} else if (rest.equals("of ") && teller == 0) { // OR
					j = i;
					i = i+3;// or is associatief
				}
			} else if (karakter.equals("n") && teller == 0 && i+4 < regex.length()) {
				String rest = new Character(letters[i+1]).toString() + new Character(letters[i+2]).toString() + new Character(letters[i+3]).toString() + new Character(letters[i+4]).toString();
				if (rest.equals("iet ")) { // NOT
					return i; // normaal enkel nul mogelijk
				}
			} else if (karakter.equals("(")) {
				teller++;
			} else if (karakter.equals(")")) {
				teller--;
			}
			i++;
		}
		return j;
	}
	
	public boolean checkOuterBrackets(String regex){
		if(!(regex.startsWith("(") && regex.endsWith(")"))){
			return false;
		}
		//Regex begint zeker met (
		char[] characters = regex.toCharArray();
		int counter = 1;
		int i = 1;
		for(i=1; i < characters.length-1; i++){
			String character = new Character(characters[i]).toString();
			if(character.equals("(")){
				counter++;
			}
			else if(character.equals(")")){
				counter--;
			}
			if(counter == 0){
				return false;
			}
		}
		return true;
	}
	
	/**
	 * Split the String 'regex' around matches of the given 'splitter'. 
	 * 
	 * @param	splitter
	 * 			| Around which the String 'regex' must be split.
	 * 
	 * @param	regex
	 * 			| The String that must be split around 'splitter'.
	 * 
	 * @return	An array of Strings of which the first element is the first result of
	 * 			the split operation and the next element is a concatenation of the
	 * 			other results of the split operation.
	 */
//	private static String[] split(String splitter, String regex) {
//		String[] split = regex.split(splitter);
//		String rest = split[1];
//		for (int i = 2; i < split.length; i++) {
//			rest += split[i];
//		}
//		String[] res = {split[0],rest};
//		return res;
//	}
	
	public abstract HashMap<String,List<FieldInfo>> join();
	
	/**
	 * Verify if info1 and info2 have the same values.
	 * 
	 * @param	info1
	 * 			| The first FieldInfo to compare.
	 * 
	 * @param	info2
	 * 			| The second FieldInfo to compare.
	 * 
	 * @return	If info 1 has the same values as info 2.
	 */
	public static boolean equalFieldInfo(FieldInfo info1, FieldInfo info2) {
		if (info1.getDescription().equals(info2.getDescription()) 
				&& info1.getValue().equals(info2.getValue()))
			return true;
		return false;
	}
	
}
